package com.smart.translator.util;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import java.util.concurrent.LinkedBlockingQueue;
import java.io.ByteArrayOutputStream;

public class AdpcmEncoder {
    private static final String TAG = "AdpcmEncoder";
    
    // IMA ADPCM step variation table (与C语言实现完全一致)
    private static final int[] stepSize = {
        7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
        19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
        50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
        130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
        337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
        876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
        2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
        5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
        15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
    };

    private static final int[] stepAdjustment = {
        -1, -1, -1, -1, 2, 4, 6, 8
    };

    // 状态变量（对应C语言的ima_adpcm_state_t结构）
    private int last;           // 对应s->last
    private int stepIndex;      // 对应s->step_index
    private int imaByte;        // 对应s->ima_byte
    private int bits;           // 对应s->bits
    private int variant;        // 对应s->variant，使用IMA_ADPCM_DVI4 = 0
    
    // 循环缓冲区队列，用于存储编码后的ADPCM数据
    private LinkedBlockingQueue<byte[]> adpcmBufferQueue;
    private static final int BUFFER_SIZE = 100; // 缓冲区大小
    private static final int WRITE_CHUNK_SIZE = 120; // 每次写入120字节
    
    // 定时器相关
    private Handler timerHandler;
    private Runnable timerRunnable;
    private static final long WRITE_INTERVAL = 50; // 50ms写入间隔
    private boolean isTimerRunning = false;
    
    // 累积PCM数据缓冲区
    private ByteArrayOutputStream pcmAccumulator = new ByteArrayOutputStream();
    
    // 循环缓冲区相关
    private byte[] pcmCircularBuffer;
    private int pcmBufferSize = 8192; // 8KB循环缓冲区
    private int pcmReadIndex = 0;
    private int pcmWriteIndex = 0;
    private int pcmDataCount = 0;
    
    // 第二个定时器相关（PCM编码定时器）
    private Handler pcmTimerHandler;
    private Runnable pcmTimerRunnable;
    private static final long PCM_PROCESS_INTERVAL = 20; // 20ms处理一次PCM
    private static final int PCM_CHUNK_SIZE = 320; // 每次处理320字节PCM数据
    private boolean isPcmTimerRunning = false;
    
    // BLE写入回调接口
    public interface BleWriteCallback {
        void onWriteAdpcmData(byte[] adpcmData);
    }
    
    private BleWriteCallback bleWriteCallback;

    public AdpcmEncoder() {
        reset();
        adpcmBufferQueue = new LinkedBlockingQueue<>(BUFFER_SIZE);
        pcmAccumulator = new ByteArrayOutputStream();
        pcmCircularBuffer = new byte[pcmBufferSize];
        timerHandler = new Handler(Looper.getMainLooper());
        pcmTimerHandler = new Handler(Looper.getMainLooper());
        initTimer();
        initPcmTimer();
    }

    public void setBleWriteCallback(BleWriteCallback callback) {
        this.bleWriteCallback = callback;
    }

    public void reset() {
        last = 0;
        stepIndex = 0;
        imaByte = 0;
        bits = 0;
        variant = 0; // IMA_ADPCM_DVI4
        
        // 重置循环缓冲区状态
        pcmReadIndex = 0;
        pcmWriteIndex = 0;
        pcmDataCount = 0;
        
        Log.d(TAG, "编码器状态已重置: last=" + last + ", stepIndex=" + stepIndex + ", imaByte=" + imaByte + ", bits=" + bits);
    }

    /**
     * 饱和函数，对应C语言的saturate函数
     */
    private int saturate(int amp) {
        if (amp > Short.MAX_VALUE)
            return Short.MAX_VALUE;
        if (amp < Short.MIN_VALUE)
            return Short.MIN_VALUE;
        return amp;
    }

    /**
     * 编码单个PCM样本，完全按照C语言实现
     */
    private byte encode(short linear) {
        int e;
        int ss;
        int adpcm;
        int diff;
        int initial_e;

        ss = stepSize[stepIndex];
        initial_e = e = linear - last;
        diff = ss >> 3;
        adpcm = 0x00;
        
        if (e < 0) {
            adpcm = 0x08;
            e = -e;
        }
        
        if (e >= ss) {
            adpcm |= 0x04;
            e -= ss;
        }
        
        ss >>= 1;
        if (e >= ss) {
            adpcm |= 0x02;
            e -= ss;
        }
        
        ss >>= 1;
        if (e >= ss) {
            adpcm |= 0x01;
            e -= ss;
        }

        // 关键：按照C语言实现计算预测值
        if (initial_e < 0)
            diff = -(diff - initial_e - e);
        else
            diff = diff + initial_e - e;
            
        last = saturate(diff + last);
        stepIndex += stepAdjustment[adpcm & 0x07];
        if (stepIndex < 0)
            stepIndex = 0;
        else if (stepIndex > 88)
            stepIndex = 88;

        return (byte) adpcm;
    }

    /**
     * 将PCM数据编码为ADPCM格式，按照C语言的ima_adpcm_encode函数实现
     */
    public byte[] encode(short[] pcmData) {
        if (pcmData == null || pcmData.length == 0)
            return new byte[0];

        // 不再重置imaByte和bits，保持编码连续性
        // 只有在reset()方法中才重置这些状态
        
        // 计算输出缓冲区大小（每两个样本一个字节，但只在bits为奇数时才写入）
        int maxOutputSize = (pcmData.length + 1) / 2;
        byte[] adpcmData = new byte[maxOutputSize];
        int bytes = 0;

        // 按照C语言实现进行编码
        for (int i = 0; i < pcmData.length; i++) {
            byte code = encode(pcmData[i]);
            imaByte = (imaByte >> 4) | (code << 4);
            if ((bits++ & 1) != 0) {
                adpcmData[bytes++] = (byte) imaByte;
            }
        }

        // 完全按照C语言实现：不处理最后一个不完整的字节
        // 创建正确大小的输出数组
        byte[] result = new byte[bytes];
        System.arraycopy(adpcmData, 0, result, 0, bytes);

        return result;
    }

    /**
     * 将PCM字节数组编码为ADPCM格式
     */
    public byte[] encodeFromBytes(byte[] pcmBytes) {
        if (pcmBytes == null || pcmBytes.length == 0)
            return new byte[0];

        // 检查字节数是否为偶数（每个PCM样本2字节）
        if (pcmBytes.length % 2 != 0) {
            Log.w(TAG, "PCM字节数不是偶数，丢弃最后一个字节: " + pcmBytes.length);
            // 创建新的字节数组，去掉最后一个字节
            byte[] evenBytes = new byte[pcmBytes.length - 1];
            System.arraycopy(pcmBytes, 0, evenBytes, 0, evenBytes.length);
            pcmBytes = evenBytes;
        }

        // 将字节数组转换为short数组（小端序）
        short[] pcmData = new short[pcmBytes.length / 2];
        for (int i = 0; i < pcmData.length; i++) {
            pcmData[i] = (short) ((pcmBytes[i * 2] & 0xFF) | (pcmBytes[i * 2 + 1] << 8));
        }

        // 添加调试信息
        if (pcmData.length > 0) {
            Log.d(TAG, "PCM数据样本: 前5个=" + pcmData[0] + "," + pcmData[1] + "," + pcmData[2] + "," + pcmData[3] + "," + pcmData[4]);
        }

        return encode(pcmData);
    }

    /**
     * 初始化定时器
     */
    private void initTimer() {
        timerRunnable = new Runnable() {
            @Override
            public void run() {
                // 从缓冲区读取数据并写入BLE
                processBufferQueue();
                
                // 如果缓冲区还有数据，继续定时器
                if (!adpcmBufferQueue.isEmpty()) {
                    timerHandler.postDelayed(this, WRITE_INTERVAL);
                } else {
                    isTimerRunning = false;
                    Log.d(TAG, "ADPCM缓冲区为空，停止定时器");
                }
            }
        };
    }

    /**
     * 启动定时器
     */
    private void startTimer() {
        if (!isTimerRunning) {
            isTimerRunning = true;
            timerHandler.postDelayed(timerRunnable, WRITE_INTERVAL);
            Log.d(TAG, "启动ADPCM写入定时器，间隔: " + WRITE_INTERVAL + "ms");
        }
    }

    /**
     * 停止定时器
     */
    private void stopTimer() {
        if (isTimerRunning) {
            isTimerRunning = false;
            timerHandler.removeCallbacks(timerRunnable);
            Log.d(TAG, "停止ADPCM写入定时器");
        }
    }

    /**
     * 处理缓冲区队列中的数据
     */
    private void processBufferQueue() {
        try {
            // 收集数据进行写入
            byte[] combinedData = new byte[WRITE_CHUNK_SIZE];
            int totalBytes = 0;
            int dataBlocksProcessed = 0;

            // 从队列中取出数据，直到达到写入块大小或队列为空
            while (totalBytes < WRITE_CHUNK_SIZE && !adpcmBufferQueue.isEmpty()) {
                byte[] data = adpcmBufferQueue.poll();
                if (data != null) {
                    dataBlocksProcessed++;
                    int copyLength = Math.min(data.length, WRITE_CHUNK_SIZE - totalBytes);
                    System.arraycopy(data, 0, combinedData, totalBytes, copyLength);
                    totalBytes += copyLength;
                    
                    Log.d(TAG, "处理数据块 " + dataBlocksProcessed + ": 长度=" + data.length + ", 复制=" + copyLength + ", 累计=" + totalBytes);
                    
                    // 如果数据没有完全复制，将剩余部分放回队列
                    if (copyLength < data.length) {
                        byte[] remainingData = new byte[data.length - copyLength];
                        System.arraycopy(data, copyLength, remainingData, 0, remainingData.length);
                        adpcmBufferQueue.offer(remainingData);
                        Log.d(TAG, "数据块未完全处理，剩余 " + remainingData.length + " 字节放回队列");
                    }
                }
            }

            // 如果有数据，写入BLE
            if (totalBytes > 0) {
                byte[] writeData = new byte[totalBytes];
                System.arraycopy(combinedData, 0, writeData, 0, totalBytes);
                
                // 打印ADPCM编码器输出的数据
                Log.d(TAG, "=== ADPCM编码器输出数据 ===");
                Log.d(TAG, "编码器数据长度: " + totalBytes + " 字节");
                Log.d(TAG, "处理数据块数: " + dataBlocksProcessed);
                Log.d(TAG, "编码器十六进制数据: " + bytesToHex(writeData));
                Log.d(TAG, "编码器时间戳: " + System.currentTimeMillis());
                Log.d(TAG, "=== 编码器数据结束 ===");
                
                Log.d(TAG, "定时器写入BLE FFF3特征: " + totalBytes + " 字节，缓冲区剩余: " + adpcmBufferQueue.size());
                
                if (bleWriteCallback != null) {
                    bleWriteCallback.onWriteAdpcmData(writeData);
                }
            }

        } catch (Exception e) {
            Log.e(TAG, "处理缓冲区队列异常", e);
        }
    }

    /**
     * 强制处理缓冲区中的所有数据
     * 注意：这个方法现在只是启动定时器，让定时器自然处理所有数据
     */
    public void flushBuffer() {
        Log.d(TAG, "强制刷新缓冲区，剩余数据: " + adpcmBufferQueue.size());
        
        // 处理剩余的PCM数据
        if (pcmDataCount > 0) {
            Log.d(TAG, "处理剩余PCM数据: " + pcmDataCount + " 字节");
            processPcmBuffer();
        }
        
        // 不停止定时器，让定时器继续处理剩余数据
        // 如果定时器没有运行，启动它
        if (!isTimerRunning && !adpcmBufferQueue.isEmpty()) {
            startTimer();
        }
        
        Log.d(TAG, "缓冲区强制刷新完成，定时器将继续处理剩余数据");
    }

    /**
     * 清空缓冲区
     */
    public void clearBuffer() {
        stopTimer();
        stopPcmTimer();
        adpcmBufferQueue.clear();
        pcmAccumulator.reset();
        // 重置循环缓冲区
        pcmReadIndex = 0;
        pcmWriteIndex = 0;
        pcmDataCount = 0;
        Log.d(TAG, "ADPCM缓冲区和PCM累积器已清空");
    }

    /**
     * 获取缓冲区大小
     */
    public int getBufferSize() {
        return adpcmBufferQueue.size();
    }

    /**
     * 测试ADPCM编码的正确性
     */
    public void testEncoding() {
        Log.d(TAG, "开始ADPCM编码测试...");
        
        // 创建测试PCM数据（正弦波）
        short[] testPcm = new short[100];
        for (int i = 0; i < testPcm.length; i++) {
            testPcm[i] = (short) (Math.sin(i * 0.1) * 1000);
        }
        
        Log.d(TAG, "测试PCM数据: 前5个=" + testPcm[0] + "," + testPcm[1] + "," + testPcm[2] + "," + testPcm[3] + "," + testPcm[4]);
        
        // 编码测试
        reset();
        byte[] adpcmData = encode(testPcm);
        
        Log.d(TAG, "编码结果: PCM=" + testPcm.length + "样本 -> ADPCM=" + adpcmData.length + "字节");
        Log.d(TAG, "压缩比: " + (testPcm.length * 2.0 / adpcmData.length));
        
        // 显示前几个ADPCM字节
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < Math.min(10, adpcmData.length); i++) {
            sb.append(String.format("%02X ", adpcmData[i]));
        }
        Log.d(TAG, "ADPCM数据(前10字节): " + sb.toString());
        
        Log.d(TAG, "ADPCM编码测试完成");
    }

    private String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X ", b));
        }
        return sb.toString();
    }

    /**
     * 初始化PCM处理定时器
     */
    private void initPcmTimer() {
        pcmTimerRunnable = new Runnable() {
            @Override
            public void run() {
                // 处理PCM缓冲区中的数据
                processPcmBuffer();
                
                // 如果PCM缓冲区还有数据，继续定时器
                if (pcmDataCount > 0) {
                    pcmTimerHandler.postDelayed(this, PCM_PROCESS_INTERVAL);
                } else {
                    isPcmTimerRunning = false;
                    Log.d(TAG, "PCM缓冲区为空，停止PCM定时器");
                }
            }
        };
    }
    
    /**
     * 启动PCM处理定时器
     */
    private void startPcmTimer() {
        if (!isPcmTimerRunning) {
            isPcmTimerRunning = true;
            pcmTimerHandler.postDelayed(pcmTimerRunnable, PCM_PROCESS_INTERVAL);
            Log.d(TAG, "启动PCM处理定时器，间隔: " + PCM_PROCESS_INTERVAL + "ms，最大处理: " + PCM_CHUNK_SIZE + " 字节");
        }
    }
    
    /**
     * 停止PCM处理定时器
     */
    private void stopPcmTimer() {
        if (isPcmTimerRunning) {
            isPcmTimerRunning = false;
            pcmTimerHandler.removeCallbacks(pcmTimerRunnable);
            Log.d(TAG, "停止PCM处理定时器");
        }
    }
    
    /**
     * 处理PCM缓冲区中的数据
     */
    private void processPcmBuffer() {
        try {
            if (pcmDataCount == 0) {
                return;
            }
            
            // 获取当前可用的数据量
            int availableBytes = pcmDataCount;
            int processBytes = Math.min(availableBytes, PCM_CHUNK_SIZE);
            
            // 从循环缓冲区读取数据
            byte[] pcmData = new byte[processBytes];
            int bytesRead = 0;
            
            // 处理可能跨越缓冲区末尾的情况
            while (bytesRead < processBytes) {
                int bytesToRead = Math.min(processBytes - bytesRead, pcmBufferSize - pcmReadIndex);
                System.arraycopy(pcmCircularBuffer, pcmReadIndex, pcmData, bytesRead, bytesToRead);
                pcmReadIndex = (pcmReadIndex + bytesToRead) % pcmBufferSize;
                bytesRead += bytesToRead;
            }
            
            // 更新数据计数
            pcmDataCount -= processBytes;
            
            // 确保PCM数据是偶数对齐的
            if (pcmData.length % 2 != 0) {
                Log.w(TAG, "PCM数据不是偶数对齐，丢弃最后一个字节: " + pcmData.length);
                byte[] evenData = new byte[pcmData.length - 1];
                System.arraycopy(pcmData, 0, evenData, 0, evenData.length);
                pcmData = evenData;
            }
            
            if (pcmData.length == 0) {
                return;
            }
            
            Log.d(TAG, "PCM定时器处理数据: " + pcmData.length + " 字节，剩余: " + pcmDataCount + " 字节");
            
            // 编码PCM数据为ADPCM
            byte[] adpcmData = encodeFromBytes(pcmData);
            Log.d(TAG, "PCM编码完成: " + pcmData.length + " -> " + adpcmData.length + " 字节");

            // 将编码后的数据放入ADPCM缓冲区
            if (!adpcmBufferQueue.offer(adpcmData)) {
                Log.w(TAG, "ADPCM缓冲区已满，丢弃数据");
            }

            // 启动ADPCM发送定时器（如果还没启动）
            startTimer();

        } catch (Exception e) {
            Log.e(TAG, "PCM缓冲区处理异常", e);
        }
    }
    
    /**
     * 处理PCM音频流
     * @param pcmBytes PCM音频数据
     */
    public void processPcmStream(byte[] pcmBytes) {
        if (pcmBytes == null || pcmBytes.length == 0) {
            Log.w(TAG, "PCM数据为空，跳过处理");
            return;
        }

        try {
            // 检查缓冲区是否有足够空间
            if (pcmBytes.length > pcmBufferSize - pcmDataCount) {
                Log.w(TAG, "PCM缓冲区空间不足，丢弃数据: " + pcmBytes.length + " 字节");
                return;
            }
            
            // 将PCM数据写入循环缓冲区
            int bytesWritten = 0;
            while (bytesWritten < pcmBytes.length) {
                int bytesToWrite = Math.min(pcmBytes.length - bytesWritten, pcmBufferSize - pcmWriteIndex);
                System.arraycopy(pcmBytes, bytesWritten, pcmCircularBuffer, pcmWriteIndex, bytesToWrite);
                pcmWriteIndex = (pcmWriteIndex + bytesToWrite) % pcmBufferSize;
                bytesWritten += bytesToWrite;
            }
            
            // 更新数据计数
            pcmDataCount += pcmBytes.length;
            
            Log.d(TAG, "累积PCM数据: " + pcmBytes.length + " 字节，缓冲区总计: " + pcmDataCount + " 字节");
            
            // 如果有数据且定时器未运行，启动PCM处理定时器
            if (pcmDataCount > 0 && !isPcmTimerRunning) {
                startPcmTimer();
            }

        } catch (Exception e) {
            Log.e(TAG, "PCM数据累积异常", e);
        }
    }
} 